﻿///////////////////////////////////////////////////////////////////////////////
// File:        Main.cc
// Author:      671643387@qq.com
// Description:
///////////////////////////////////////////////////////////////////////////////

#include <csignal>
#if defined(__WINDOWS__)
#include <crtdbg.h>
#endif
#include <vector>
#include <iostream>
#include <boost/program_options.hpp>

#include "Summary.hpp"
#include "Worker.hpp"
namespace po = boost::program_options;

bool gExit = false;
Summary gSummary;

void signal_handler(int signal)
{
    if (signal == SIGINT)
    {
        gExit = true;
    }
}

int main(int argc, char* argv[])
{
    {
        std::string addr;
        int port = 0;
        int workers = 0;
        int clients_per_worker = 0;
        unsigned int buffSize = 0;
        std::string message;

        {
            po::options_description desc("Options");
            desc.add_options()
                ("help,h", "Help")
                ("address,a", po::value<std::string>()->default_value("127.0.0.1"), "Server Address")
                ("port,p", po::value<int>()->default_value(8888), "Server Port")
                ("workers,w", po::value<int>()->default_value(1), "Threads")
                ("cpw,c", po::value<int>()->default_value(1), "Connection Per Thread")
                ("bs,s", po::value<unsigned int>()->default_value(0x1000), "Message Size")
                ("message,m", po::value<std::string>()->default_value("01010101"), "Message");

            po::variables_map vm;
            po::store(po::parse_command_line(argc, argv, desc), vm);

            if (vm.count("help"))
            {
                std::cout << desc << std::endl;
                return 0;
            }

            addr = vm["address"].as<std::string>();
            port = vm["port"].as<int>();
            workers = vm["workers"].as<int>();
            clients_per_worker = vm["cpw"].as<int>();
            buffSize = vm["bs"].as<unsigned int>();
            message = vm["message"].as<std::string>();
        }

#if defined(__WINDOWS__)
        WSADATA wsaData;
        WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif
        signal(SIGINT, signal_handler);
        
        std::vector<WorkerPtr> workerArr;
        for (int x = 0; x < workers; ++x)
        {
            WorkerPtr worker(new Worker());
            if (worker->open(addr, port, buffSize, clients_per_worker, message) 
                && worker->start())
            {
                workerArr.push_back(worker);
            }
        }

        // DUMP
        while (!gExit && (gSummary.getLoad() > 0))
        {
            nio::base::Thread::sleep(1000);
            gSummary.dump();
        }

        for (std::vector<WorkerPtr>::size_type x = 0; x < workerArr.size(); ++x)
        {
            workerArr[x]->stop();
            workerArr[x]->join();
        }
    }

#if defined(__WINDOWS__)
    WSACleanup();
    _CrtDumpMemoryLeaks();
#endif
    return 0;
}